package com.spzx.cart.service.impl;

import com.spzx.cart.api.domain.CartInfo;
import com.spzx.cart.service.ICartService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.context.SecurityContextHolder;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.product.api.RemoteProductService;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.vo.SkuPrice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements ICartService {


    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    private RemoteProductService remoteProductService;

    //用来生成Hash类型大key
    private String getCartKey(Long userId) {
        return "user:cart:" + userId;
    }

    @Override
    public void addToCart(Long skuId, Integer skuNum) {
        Long userId = SecurityContextHolder.getUserId(); // HeaderInterceptor 拦截器存放到线程上，从线程上可以取到用户id.
        String cartKey = getCartKey(userId); //大key

        String hashKey = skuId.toString(); //小key

        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        CartInfo cartInfo = hashOps.get(hashKey);
        Integer thresHold = 99;


        R<ProductSku> productSkuResult = remoteProductService.getProductSku(skuId, SecurityConstants.INNER);
        if (R.FAIL == productSkuResult.getCode()) {
            throw new ServiceException(productSkuResult.getMsg());
        }
        ProductSku productSku = productSkuResult.getData();
        if (cartInfo != null) {//2.再次添加
            Integer totalNum = cartInfo.getSkuNum() + skuNum; //单品上线不能超过99
            cartInfo.setSkuNum(totalNum > thresHold ? thresHold : totalNum);
            cartInfo.setSkuPrice(productSku.getSalePrice()); //商品实时价格。在显示购物车列表时可以变实时价格。存储缓存时，该不该实时价格都行。
            cartInfo.setUpdateTime(new Date());
            hashOps.put(hashKey, cartInfo);
        } else { //1.首次添加

            Long count = hashOps.size();
            if (++count > 50) {
                throw new RuntimeException("商品种类数量超过上限！");
            }

            cartInfo = new CartInfo();
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);

            cartInfo.setCartPrice(productSku.getSalePrice()); //当时添加购物车时商品价格
            cartInfo.setSkuPrice(productSku.getSalePrice()); //实时价格

            cartInfo.setSkuNum(skuNum > thresHold ? thresHold : skuNum);
            cartInfo.setThumbImg(productSku.getThumbImg());
            cartInfo.setSkuName(productSku.getSkuName());
            cartInfo.setCreateTime(new Date());
            cartInfo.setUpdateTime(new Date());
            hashOps.put(hashKey, cartInfo);
        }
    }


    @Override
    public List<CartInfo> getCartList() {
        Long userId = SecurityContextHolder.getUserId(); // HeaderInterceptor 拦截器存放到线程上，从线程上可以取到用户id.
        String cartKey = getCartKey(userId); //大key

        List<CartInfo> cartInfoList = redisTemplate.boundHashOps(cartKey).values();
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            //1.显示购物车时需要根据添加时间倒序
            List<CartInfo> infoList = cartInfoList.stream().sorted((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime())).collect(Collectors.toList());

            //2.更新实时价格
            List<Long> skuIdList = infoList.stream().map(cartInfo -> cartInfo.getSkuId()).collect(Collectors.toList());
            R<List<SkuPrice>> skuPriceListResult = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);
            if (R.FAIL == skuPriceListResult.getCode()) {
                throw new ServiceException(skuPriceListResult.getMsg());
            }
            List<SkuPrice> skuPriceList = skuPriceListResult.getData(); //数据库最新价格
            Map<Long, BigDecimal> skuIdToSalePriceMap = skuPriceList.stream().collect(Collectors.toMap(SkuPrice::getSkuId, SkuPrice::getSalePrice));

            infoList.forEach(cartInfo -> {
                cartInfo.setSkuPrice(skuIdToSalePriceMap.get(cartInfo.getSkuId()));
            });

            return infoList;
        }
        return new ArrayList<>(); //购物车没东西，返回空集合对象。
    }


    @Override
    public void deleteCart(Long skuId) {
        Long userId = SecurityContextHolder.getUserId(); // HeaderInterceptor 拦截器存放到线程上，从线程上可以取到用户id.
        String cartKey = getCartKey(userId); //大key

        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        //java.lang.ClassCastException: class java.lang.Long cannot be cast to class java.lang.String (java.lang.Long and java.lang.String are in module java.base of loader 'bootstrap')
        hashOps.delete(skuId.toString());
    }

    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        Long userId = SecurityContextHolder.getUserId(); // HeaderInterceptor 拦截器存放到线程上，从线程上可以取到用户id.
        String cartKey = getCartKey(userId); //大key
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        if (hashOps.hasKey(skuId.toString())) {
            CartInfo cartInfo = hashOps.get(skuId.toString());
            cartInfo.setIsChecked(isChecked);
            hashOps.put(skuId.toString(), cartInfo);
        }
    }

    @Override
    public void allCheckCart(Integer isChecked) {
        Long userId = SecurityContextHolder.getUserId(); // HeaderInterceptor 拦截器存放到线程上，从线程上可以取到用户id.
        String cartKey = getCartKey(userId); //大key
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = hashOps.values();
        cartInfoList.forEach(cartInfo -> {
            cartInfo.setIsChecked(isChecked);
            hashOps.put(cartInfo.getSkuId().toString(), cartInfo);
        });
    }

    @Override
    public void clearCart() {
        Long userId = SecurityContextHolder.getUserId(); // HeaderInterceptor 拦截器存放到线程上，从线程上可以取到用户id.
        String cartKey = getCartKey(userId); //大key
        redisTemplate.delete(cartKey);
    }


    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {
        String cartKey = getCartKey(userId); //大key
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartKey);
        //List<CartInfo> cartInfoList = redisTemplate.boundHashOps(cartKey).values();
        List<CartInfo> cartInfoCheckedList = cartInfoList.stream()
                .filter(cartInfo -> cartInfo.getIsChecked().intValue() == 1).toList();
        return cartInfoCheckedList;
    }

    /**
     * 更新用户购物车列表价格
     *
     * @param userId
     * @return
     */
    @Override
    public Boolean updateCartPrice(Long userId) {
        String cartKey = getCartKey(userId); //大key
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartKey);
        for (CartInfo cartInfo : cartInfoList) {
            Long skuId = cartInfo.getSkuId();
            R<SkuPrice> skuPriceResult = remoteProductService.getSkuPrice(skuId, SecurityConstants.INNER);
            if (R.FAIL == skuPriceResult.getCode()) {
                throw new ServiceException(skuPriceResult.getMsg());
            }
            SkuPrice skuPrice = skuPriceResult.getData(); //最新价格
            if (cartInfo.getSkuPrice().compareTo(skuPrice.getSalePrice()) != 0) { //比较BigDecimal类型值大小。使用Comparable接口的compareTo()方法
                cartInfo.setCartPrice(skuPrice.getSalePrice()); // cartPrice应该是经过优惠处理后价格。
                cartInfo.setSkuPrice(skuPrice.getSalePrice());
                redisTemplate.boundHashOps(cartKey).put(cartInfo.getSkuId().toString(),cartInfo);
            }
        }
        return true;
    }


    @Override
    public Boolean deleteCartCheckedList(Long userId) {
        String cartKey = getCartKey(userId); //大key
        BoundHashOperations<String,String,CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = hashOps.values();
        if(!CollectionUtils.isEmpty(cartInfoList)){
            for (CartInfo cartInfo : cartInfoList) {
                if(cartInfo.getIsChecked() == 1){
                    hashOps.delete(cartInfo.getSkuId().toString());
                }
            }
        }
        return true;
    }
}
